package com.jivam.lottery.util;


import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

public class ExpressionUtil {
	
	private final static Map<Character,Integer> PRIORITIES = new HashMap<Character,Integer>();
	private final static char PLUS = '+';
	private final static char MINUS = '-';
	private final static char TIMES = '*';
	private final static char DIVISION = '/';
	private final static char OPEN_PARENTHESIS = '(';
	private final static char CLOSE_PARENTHESIS = ')';
	private final static char OPEN_BRACE = '{';
	private final static char CLOSE_BRACE = '}';
	
	static{
		PRIORITIES.put(OPEN_PARENTHESIS, 9);
		PRIORITIES.put(CLOSE_PARENTHESIS, 9);
		PRIORITIES.put(DIVISION, 8);
		PRIORITIES.put(TIMES, 8);
		PRIORITIES.put(MINUS, 7);
		PRIORITIES.put(PLUS, 7);
	}
	
	private ExpressionUtil(){
	}
	
	/**
	 * 针对操作数添加括号，乘除包含括号的话要放到前面
	 * 2+3*(1+2)+2.1 -> {2}+{3}*({1}+{2})+{2.1}
	 * @param expression
	 * @return
	 */
	private static String getFullExpression(String expression){
		StringBuilder result = new StringBuilder();
		Character current = null ,next = null;
		boolean lastIsOperator = true;//默认是操作符，这样以'('开始的不会在condition:0出现Bug
		char[] array = expression.toCharArray();
		if(array[0] != OPEN_PARENTHESIS)//不是从'('开始的，第一个操作符添加'{'
			result.append(OPEN_BRACE);
		for(int i = 0 ; i < array.length ; i++){
			current = array[i];
			if(i+1 < array.length){//没有处理最后一位的next数值，因为末尾不会出现除')'之外的操作符
				next = array[i+1];//因此最后一位的next只可能是走branch:0 - condition:0或branch:1 因为不会通过condition:1出现bug
			}
			if(PRIORITIES.containsKey(current)){//branch:0 当前是操作符
				if(!lastIsOperator){//condition:0 上一个不是操作符
					result.append(CLOSE_BRACE);
				}
				result.append(current);
				if(OPEN_PARENTHESIS == current 
						|| (CLOSE_PARENTHESIS != current && next != OPEN_PARENTHESIS)){//condition:1
					//condition:1 是'('后面一定是操作数 或 非括号操作符(后面只可能包含一种操作符'(')并且下一个不是'('
					result.append(OPEN_BRACE);
				}
				lastIsOperator = true;//上一位是操作符
			}else{//branch:1 非操作符
				result.append(current);//非操作符
				lastIsOperator = false;//上一位不是操作符
			}
		}
		if(current != CLOSE_PARENTHESIS)//不是以')'结尾的，最后一个操作符添加'}'
			result.append(CLOSE_BRACE);
		return result.toString();
	}

	/**
	 * 把表达式用前缀表达式表示，乘除包含括号的话要放到前面
	 * @param expression 表达式
	 * @return 前缀表达式
	 */
	public static String getPostfixExp(String expression){
		if(expression == null || expression.isEmpty())
			return null;
		if(expression.indexOf(OPEN_BRACE) == -1)
			expression = getFullExpression(expression);
		LinkedList<Character> opStack = new LinkedList<Character>();
		StringBuilder result = new StringBuilder();
		char op;
		for(Character c : expression.toCharArray()){
			if(PRIORITIES.containsKey(c)){// is operator
				if(OPEN_PARENTHESIS == c){
					opStack.offerLast(c);
				}else if(CLOSE_PARENTHESIS == c){
					while(opStack.size()>0){
						op = opStack.pollLast();
						if(OPEN_PARENTHESIS != op){
							result.append(op);
						}
					}
				}else{
					if(opStack.size() > 0){
						op = opStack.peekLast();
						if(OPEN_PARENTHESIS != op && PRIORITIES.get(c) <= PRIORITIES.get(op)){
							result.append(opStack.pollLast());
						}
					}
					opStack.offerLast(c);
				}
			}else{
				result.append(c);
			}
		}
		while(opStack.size()>0){
			result.append(opStack.removeLast());
		}
		return result.toString();
	}
	
	/**
	 * 专门为彩票结果设计的计算，结果会取绝对值并只返回个位数字
	 * @param postfix 前缀表达式
	 * @param dict 字典
	 * @return
	 */
	public static Integer getValueByPostfixForLottery(String postfix,Map<String,Integer> dict){
		Float f = getValueByPostfix(postfix,dict);
		f = Math.abs(f);
		return Math.round(f)%10;
	}
	
	/**
	 * 通过前缀表达式获得计算结果
	 * @param postfix 前缀表达式
	 * @param dict 字典
	 * @return
	 */
	public static Float getValueByPostfix(String postfix,Map<String,Integer> dict){
		if(postfix == null || postfix.isEmpty())
			return null;
		LinkedList<Float> numStack = new LinkedList<Float>();
		StringBuilder tempDield = new StringBuilder();
		Float temp = null,left,right;
		for(Character c: postfix.toCharArray()){
			if(PRIORITIES.containsKey(c)){
				right = numStack.pollLast();
				left = numStack.pollLast();
				if(PLUS == c){
					temp = left+right;
				}else if(MINUS == c){
					temp = left-right;
				}else if(TIMES == c){
					temp = left*right;
				}else if(DIVISION == c){
					temp = left/right;
				}
			}else{
				if(OPEN_BRACE == c){
					continue;
				}else if(CLOSE_BRACE == c){
					if(dict != null && dict.containsKey(tempDield.toString()))
						temp = dict.get(tempDield.toString()).floatValue();
					else
						temp = Float.valueOf(tempDield.toString());
					tempDield.setLength(0);
				}else{
					tempDield.append(c);
					continue;
				}
			}
			numStack.offerLast(temp);
		}
		return numStack.getFirst();
	}
	
	public static void main(String[] args) {
		HashMap<String,Integer> dict = new HashMap<String,Integer>();
		dict.put("a", 1);
		dict.put("b", 2);
		dict.put("c", 3);
		String expression = "10-41.5";
		System.out.println(expression);
		expression = getFullExpression(expression);
		System.out.println(expression);
		expression = getPostfixExp(expression);
		System.out.println(expression);
		System.out.println(getValueByPostfix(expression, dict));
		System.out.println(getValueByPostfixForLottery(expression, dict));
		
	}
	
	
}
